Leaflet

Introduction to Leaflet in R

Basic Usage

Create map widget with leaflet()

library(leaflet)
library(sf)
Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1
beetle_url <- "https://raw.githubusercontent.com/dyerlab/ENVS-Lectures/master/data/Araptus_Disperal_Bias.csv"
beetle <- read.csv(beetle_url)

beetle <- beetle %>%
   st_as_sf( coords=c("Longitude","Latitude"), crs=4326 )

Add a basemap with addTiles(). By default OpenStreetMap tiles are used.

leaflet() %>%
  setView(lng = -77.5, lat = 37.5, zoom = 10) %>% #not necessary to set your view
  addTiles()
#blank map because we haven't added any layers

Third party tiles

Use addProviderTiles() function to use a different basemap.

See here for all options

leaflet() %>%
  setView(lng = -77.5, lat = 37.5, zoom = 10) %>% #not necessary to set your view
  addProviderTiles(providers$CartoDB.Positron)

Data Objects

  • dataframe with lat/lng columns
  • sp objects
  • sf objects
  • maps package map() objects

Data can be passed through the leaflet() function or through the map layers.

#These make the same map

leaflet(beetle) %>%
  addTiles() %>%
  addCircles()
leaflet() %>%
  addTiles() %>%
  addCircles(data = beetle)

Points, lines and Polygons

Points can be plotted using addMarkers() or addCircles() - Markers stay the same size regardless of zoom level - Circles scale with the map

leaflet(beetle) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  addMarkers()

Custom Markers - Custom markers can be made using a url/image file or from libraries

bug <- icons(
  iconUrl = "https://www.pngfind.com/pngs/m/14-144860_beetle-bug-png-transparent-image-bug-png-png.png",
  iconWidth = 20,
  iconHeight = 20
)
leaflet(beetle) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  addMarkers(icon = bug)

link to Font Awesome library

fa_bug <- makeAwesomeIcon(icon = "bug", library = "fa", 
                          markerColor = "cadetblue", iconColor = "beige")

leaflet(beetle) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  addAwesomeMarkers(icon = fa_bug)

Popups can be added as a stand-alone feature using addPopups(), or add to appear when a shape is clicked

#stand-alone

leaflet(beetle) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  setView(lng = -111, lat = 25, zoom = 7) %>%
  addPopups(lng = -111, lat = 25, paste0("beetles live here"))
#as a part of a marker

leaflet(beetle) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  addAwesomeMarkers(icon = fa_bug, popup = paste0("Site:", beetle$Site))

Labels

Use label = to add a label displayed on a mouse over

leaflet(beetle) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  addAwesomeMarkers(icon = fa_bug, label = paste0("Site:", beetle$Site))

addCircles()

leaflet(beetle) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  addCircles()

Change radius:

leaflet(beetle) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  addCircles(radius = ~Males *500, stroke = FALSE, fillOpacity = .5)

Change color:

pal <- colorNumeric(
  palette = "RdBu",
  domain = beetle$MFRatio
)


leaflet(beetle) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  addCircles(color = ~rev(pal(MFRatio)), fillOpacity = .7, radius = 15000, stroke = FALSE)

Highlight

leaflet(beetle) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  addCircles(fillColor = ~rev(pal(MFRatio)), fillOpacity = .7, radius = 15000, 
             weight = 1, color = "grey",
  highlightOptions = highlightOptions(color = "green", weight = 2,
      bringToFront = TRUE))

Polygons

library(tidyverse)
-- Attaching packages --------------------------------------- tidyverse 1.3.0 --
v ggplot2 3.3.3     v purrr   0.3.4
v tibble  3.0.5     v dplyr   1.0.4
v tidyr   1.1.2     v stringr 1.4.0
v readr   1.4.0     v forcats 0.5.1
Warning: package 'dplyr' was built under R version 4.0.4
-- Conflicts ------------------------------------------ tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(tigris)
To enable 
caching of data, set `options(tigris_use_cache = TRUE)` in your R script or .Rprofile.
options(tigris_use_cache = TRUE)

tracts <- tracts("VA", "Richmond city") %>%
  st_transform(4326)

leaflet(tracts) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  addPolygons()

Add scale bar with addScaleBar()

pal <- colorNumeric(palette = "Blues",
                    domain = tracts$ALAND/2.59e+6)

leaflet(tracts) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  addPolygons(fillColor = ~pal(ALAND/2.59e+6),  fillOpacity = 1, smoothFactor = .2,
              color = "darkgrey", weight = 1,
                highlightOptions = highlightOptions(color = "white", weight = 2, opacity = 1,
                bringToFront = TRUE),
              label = paste(round(tracts$ALAND/2.59e+6, digits = 2), "sq. mi.")
              ) %>%
  addLegend(pal = pal, values = ~ALAND/2.59e+6, title = "Area (sq. miles)") %>%
  addScaleBar(position = "bottomright")

Leaflet Extras

addDrawToolbar()

library(leaflet.extras)

leaflet(tracts) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  addPolygons(fillColor = ~pal(ALAND/2.59e+6),  fillOpacity = 1, smoothFactor = .2,
              color = "darkgrey", weight = 1,
                highlightOptions = highlightOptions(color = "white", weight = 2, opacity = 1,
                bringToFront = TRUE),
              label = paste(round(tracts$ALAND/2.59e+6, digits = 2), "sq. mi.")
              ) %>%
  addLegend(pal = pal, values = ~ALAND/2.59e+6, title = "Area (sq. miles)") %>%
  addScaleBar(position = "bottomright") %>%
  addDrawToolbar()
LS0tDQp0aXRsZTogIkxlYWZsZXQiDQphdXRob3I6ICJDaGFyaXMgRGVhZHd5bGVyIg0KZGF0ZTogIjMvMTUvMjAyMSINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCiMjIExlYWZsZXQNCg0KW0ludHJvZHVjdGlvbiB0byBMZWFmbGV0IGluIFJdKGh0dHBzOi8vcnN0dWRpby5naXRodWIuaW8vbGVhZmxldC8pDQoNCiMjIyBCYXNpYyBVc2FnZQ0KDQpDcmVhdGUgbWFwIHdpZGdldCB3aXRoIGBsZWFmbGV0KClgDQoNCmBgYHtyfQ0KbGlicmFyeShsZWFmbGV0KQ0KbGlicmFyeShzZikNCg0KYmVldGxlX3VybCA8LSAiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2R5ZXJsYWIvRU5WUy1MZWN0dXJlcy9tYXN0ZXIvZGF0YS9BcmFwdHVzX0Rpc3BlcmFsX0JpYXMuY3N2Ig0KYmVldGxlIDwtIHJlYWQuY3N2KGJlZXRsZV91cmwpDQoNCmJlZXRsZSA8LSBiZWV0bGUgJT4lDQogICBzdF9hc19zZiggY29vcmRzPWMoIkxvbmdpdHVkZSIsIkxhdGl0dWRlIiksIGNycz00MzI2ICkNCmBgYA0KDQpBZGQgYSBiYXNlbWFwIHdpdGggYGFkZFRpbGVzKClgLiBCeSBkZWZhdWx0IE9wZW5TdHJlZXRNYXAgdGlsZXMgYXJlIHVzZWQuIA0KDQpgYGB7cn0NCmxlYWZsZXQoKSAlPiUNCiAgc2V0VmlldyhsbmcgPSAtNzcuNSwgbGF0ID0gMzcuNSwgem9vbSA9IDEwKSAlPiUgI25vdCBuZWNlc3NhcnkgdG8gc2V0IHlvdXIgdmlldw0KICBhZGRUaWxlcygpDQoNCiNibGFuayBtYXAgYmVjYXVzZSB3ZSBoYXZlbid0IGFkZGVkIGFueSBsYXllcnMNCmBgYA0KDQojIyMgVGhpcmQgcGFydHkgdGlsZXMNCg0KVXNlIGBhZGRQcm92aWRlclRpbGVzKClgIGZ1bmN0aW9uIHRvIHVzZSBhIGRpZmZlcmVudCBiYXNlbWFwLiANCg0KW1NlZSBoZXJlXShodHRwOi8vbGVhZmxldC1leHRyYXMuZ2l0aHViLmlvL2xlYWZsZXQtcHJvdmlkZXJzL3ByZXZpZXcvaW5kZXguaHRtbCkgZm9yIGFsbCBvcHRpb25zDQoNCmBgYHtyfQ0KbGVhZmxldCgpICU+JQ0KICBzZXRWaWV3KGxuZyA9IC03Ny41LCBsYXQgPSAzNy41LCB6b29tID0gMTApICU+JSAjbm90IG5lY2Vzc2FyeSB0byBzZXQgeW91ciB2aWV3DQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIuUG9zaXRyb24pDQpgYGANCg0KIyMjIERhdGEgT2JqZWN0cw0KDQotIGRhdGFmcmFtZSB3aXRoIGxhdC9sbmcgY29sdW1ucw0KLSBgc3BgIG9iamVjdHMNCi0gYHNmYCBvYmplY3RzDQotIGBtYXBzYCBwYWNrYWdlIGBtYXAoKWAgb2JqZWN0cw0KDQoNCkRhdGEgY2FuIGJlIHBhc3NlZCB0aHJvdWdoIHRoZSBgbGVhZmxldCgpYCBmdW5jdGlvbiBvciB0aHJvdWdoIHRoZSBtYXAgbGF5ZXJzLiANCmBgYHtyfQ0KI1RoZXNlIG1ha2UgdGhlIHNhbWUgbWFwDQoNCmxlYWZsZXQoYmVldGxlKSAlPiUNCiAgYWRkVGlsZXMoKSAlPiUNCiAgYWRkQ2lyY2xlcygpDQoNCmxlYWZsZXQoKSAlPiUNCiAgYWRkVGlsZXMoKSAlPiUNCiAgYWRkQ2lyY2xlcyhkYXRhID0gYmVldGxlKQ0KYGBgDQoNCg0KIyMjIFBvaW50cywgbGluZXMgYW5kIFBvbHlnb25zDQoNClBvaW50cyBjYW4gYmUgcGxvdHRlZCB1c2luZyBgYWRkTWFya2VycygpYCBvciBgYWRkQ2lyY2xlcygpYA0KLSBNYXJrZXJzIHN0YXkgdGhlIHNhbWUgc2l6ZSByZWdhcmRsZXNzIG9mIHpvb20gbGV2ZWwNCi0gQ2lyY2xlcyBzY2FsZSB3aXRoIHRoZSBtYXANCg0KYGBge3J9DQpsZWFmbGV0KGJlZXRsZSkgJT4lDQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIuUG9zaXRyb24pICU+JQ0KICBhZGRNYXJrZXJzKCkNCmBgYA0KDQpDdXN0b20gTWFya2Vycw0KLSBDdXN0b20gbWFya2VycyBjYW4gYmUgbWFkZSB1c2luZyBhIHVybC9pbWFnZSBmaWxlIG9yIGZyb20gbGlicmFyaWVzIA0KDQpgYGB7cn0NCmJ1ZyA8LSBpY29ucygNCiAgaWNvblVybCA9ICJodHRwczovL3d3dy5wbmdmaW5kLmNvbS9wbmdzL20vMTQtMTQ0ODYwX2JlZXRsZS1idWctcG5nLXRyYW5zcGFyZW50LWltYWdlLWJ1Zy1wbmctcG5nLnBuZyIsDQogIGljb25XaWR0aCA9IDIwLA0KICBpY29uSGVpZ2h0ID0gMjANCikNCmBgYA0KDQpgYGB7cn0NCmxlYWZsZXQoYmVldGxlKSAlPiUNCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Qb3NpdHJvbikgJT4lDQogIGFkZE1hcmtlcnMoaWNvbiA9IGJ1ZykNCmBgYA0KDQpbbGluayB0byBGb250IEF3ZXNvbWUgbGlicmFyeV0oaHR0cHM6Ly9mb250YXdlc29tZS5jb20vaWNvbnM/ZD1nYWxsZXJ5JnA9MiZtPWZyZWUpDQoNCmBgYHtyfQ0KZmFfYnVnIDwtIG1ha2VBd2Vzb21lSWNvbihpY29uID0gImJ1ZyIsIGxpYnJhcnkgPSAiZmEiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgbWFya2VyQ29sb3IgPSAiY2FkZXRibHVlIiwgaWNvbkNvbG9yID0gImJlaWdlIikNCg0KbGVhZmxldChiZWV0bGUpICU+JQ0KICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRDYXJ0b0RCLlBvc2l0cm9uKSAlPiUNCiAgYWRkQXdlc29tZU1hcmtlcnMoaWNvbiA9IGZhX2J1ZykNCg0KYGBgDQoNClBvcHVwcyBjYW4gYmUgYWRkZWQgYXMgYSBzdGFuZC1hbG9uZSBmZWF0dXJlIHVzaW5nIGBhZGRQb3B1cHMoKWAsIG9yIGFkZCB0byBhcHBlYXIgd2hlbiBhIHNoYXBlIGlzIGNsaWNrZWQNCg0KYGBge3J9DQojc3RhbmQtYWxvbmUNCg0KbGVhZmxldChiZWV0bGUpICU+JQ0KICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRDYXJ0b0RCLlBvc2l0cm9uKSAlPiUNCiAgc2V0VmlldyhsbmcgPSAtMTExLCBsYXQgPSAyNSwgem9vbSA9IDcpICU+JQ0KICBhZGRQb3B1cHMobG5nID0gLTExMSwgbGF0ID0gMjUsIHBhc3RlMCgiYmVldGxlcyBsaXZlIGhlcmUiKSkNCg0KDQpgYGANCg0KYGBge3J9DQojYXMgYSBwYXJ0IG9mIGEgbWFya2VyDQoNCmxlYWZsZXQoYmVldGxlKSAlPiUNCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Qb3NpdHJvbikgJT4lDQogIGFkZEF3ZXNvbWVNYXJrZXJzKGljb24gPSBmYV9idWcsIHBvcHVwID0gcGFzdGUwKCJTaXRlOiIsIGJlZXRsZSRTaXRlKSkNCg0KYGBgDQoNCg0KTGFiZWxzDQoNClVzZSBgbGFiZWwgPSBgIHRvIGFkZCBhIGxhYmVsIGRpc3BsYXllZCBvbiBhIG1vdXNlIG92ZXINCmBgYHtyfQ0KbGVhZmxldChiZWV0bGUpICU+JQ0KICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRDYXJ0b0RCLlBvc2l0cm9uKSAlPiUNCiAgYWRkQXdlc29tZU1hcmtlcnMoaWNvbiA9IGZhX2J1ZywgbGFiZWwgPSBwYXN0ZTAoIlNpdGU6IiwgYmVldGxlJFNpdGUpKQ0KYGBgDQoNCg0KYGFkZENpcmNsZXMoKWANCmBgYHtyfQ0KbGVhZmxldChiZWV0bGUpICU+JQ0KICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRDYXJ0b0RCLlBvc2l0cm9uKSAlPiUNCiAgYWRkQ2lyY2xlcygpDQpgYGANCg0KDQpDaGFuZ2UgcmFkaXVzOg0KYGBge3J9DQpsZWFmbGV0KGJlZXRsZSkgJT4lDQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIuUG9zaXRyb24pICU+JQ0KICBhZGRDaXJjbGVzKHJhZGl1cyA9IH5NYWxlcyAqNTAwLCBzdHJva2UgPSBGQUxTRSwgZmlsbE9wYWNpdHkgPSAuNSkNCg0KYGBgDQoNCkNoYW5nZSBjb2xvcjoNCmBgYHtyfQ0KcGFsIDwtIGNvbG9yTnVtZXJpYygNCiAgcGFsZXR0ZSA9ICJSZEJ1IiwNCiAgZG9tYWluID0gYmVldGxlJE1GUmF0aW8NCikNCg0KDQpsZWFmbGV0KGJlZXRsZSkgJT4lDQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIuUG9zaXRyb24pICU+JQ0KICBhZGRDaXJjbGVzKGNvbG9yID0gfnJldihwYWwoTUZSYXRpbykpLCBmaWxsT3BhY2l0eSA9IC43LCByYWRpdXMgPSAxNTAwMCwgc3Ryb2tlID0gRkFMU0UpDQpgYGANCg0KSGlnaGxpZ2h0DQoNCmBgYHtyfQ0KbGVhZmxldChiZWV0bGUpICU+JQ0KICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRDYXJ0b0RCLlBvc2l0cm9uKSAlPiUNCiAgYWRkQ2lyY2xlcyhmaWxsQ29sb3IgPSB+cmV2KHBhbChNRlJhdGlvKSksIGZpbGxPcGFjaXR5ID0gLjcsIHJhZGl1cyA9IDE1MDAwLCANCiAgICAgICAgICAgICB3ZWlnaHQgPSAxLCBjb2xvciA9ICJncmV5IiwNCiAgaGlnaGxpZ2h0T3B0aW9ucyA9IGhpZ2hsaWdodE9wdGlvbnMoY29sb3IgPSAiZ3JlZW4iLCB3ZWlnaHQgPSAyLA0KICAgICAgYnJpbmdUb0Zyb250ID0gVFJVRSkpDQpgYGANCg0KUG9seWdvbnMNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHRpZ3JpcykNCm9wdGlvbnModGlncmlzX3VzZV9jYWNoZSA9IFRSVUUpDQoNCnRyYWN0cyA8LSB0cmFjdHMoIlZBIiwgIlJpY2htb25kIGNpdHkiKSAlPiUNCiAgc3RfdHJhbnNmb3JtKDQzMjYpDQoNCmxlYWZsZXQodHJhY3RzKSAlPiUNCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Qb3NpdHJvbikgJT4lDQogIGFkZFBvbHlnb25zKCkNCg0KYGBgDQoNCg0KQWRkIHNjYWxlIGJhciB3aXRoIGBhZGRTY2FsZUJhcigpYA0KYGBge3J9DQoNCnBhbCA8LSBjb2xvck51bWVyaWMocGFsZXR0ZSA9ICJCbHVlcyIsDQogICAgICAgICAgICAgICAgICAgIGRvbWFpbiA9IHRyYWN0cyRBTEFORC8yLjU5ZSs2KQ0KDQpsZWFmbGV0KHRyYWN0cykgJT4lDQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIuUG9zaXRyb24pICU+JQ0KICBhZGRQb2x5Z29ucyhmaWxsQ29sb3IgPSB+cGFsKEFMQU5ELzIuNTllKzYpLCAgZmlsbE9wYWNpdHkgPSAxLCBzbW9vdGhGYWN0b3IgPSAuMiwNCiAgICAgICAgICAgICAgY29sb3IgPSAiZGFya2dyZXkiLCB3ZWlnaHQgPSAxLA0KICAgICAgICAgICAgICAgIGhpZ2hsaWdodE9wdGlvbnMgPSBoaWdobGlnaHRPcHRpb25zKGNvbG9yID0gIndoaXRlIiwgd2VpZ2h0ID0gMiwgb3BhY2l0eSA9IDEsDQogICAgICAgICAgICAgICAgYnJpbmdUb0Zyb250ID0gVFJVRSksDQogICAgICAgICAgICAgIGxhYmVsID0gcGFzdGUocm91bmQodHJhY3RzJEFMQU5ELzIuNTllKzYsIGRpZ2l0cyA9IDIpLCAic3EuIG1pLiIpDQogICAgICAgICAgICAgICkgJT4lDQogIGFkZExlZ2VuZChwYWwgPSBwYWwsIHZhbHVlcyA9IH5BTEFORC8yLjU5ZSs2LCB0aXRsZSA9ICJBcmVhIChzcS4gbWlsZXMpIikgJT4lDQogIGFkZFNjYWxlQmFyKHBvc2l0aW9uID0gImJvdHRvbXJpZ2h0IikNCg0KYGBgDQoNCg0KTGVhZmxldCBFeHRyYXMNCg0KYGFkZERyYXdUb29sYmFyKClgDQpgYGB7cn0NCmxpYnJhcnkobGVhZmxldC5leHRyYXMpDQoNCmxlYWZsZXQodHJhY3RzKSAlPiUNCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Qb3NpdHJvbikgJT4lDQogIGFkZFBvbHlnb25zKGZpbGxDb2xvciA9IH5wYWwoQUxBTkQvMi41OWUrNiksICBmaWxsT3BhY2l0eSA9IDEsIHNtb290aEZhY3RvciA9IC4yLA0KICAgICAgICAgICAgICBjb2xvciA9ICJkYXJrZ3JleSIsIHdlaWdodCA9IDEsDQogICAgICAgICAgICAgICAgaGlnaGxpZ2h0T3B0aW9ucyA9IGhpZ2hsaWdodE9wdGlvbnMoY29sb3IgPSAid2hpdGUiLCB3ZWlnaHQgPSAyLCBvcGFjaXR5ID0gMSwNCiAgICAgICAgICAgICAgICBicmluZ1RvRnJvbnQgPSBUUlVFKSwNCiAgICAgICAgICAgICAgbGFiZWwgPSBwYXN0ZShyb3VuZCh0cmFjdHMkQUxBTkQvMi41OWUrNiwgZGlnaXRzID0gMiksICJzcS4gbWkuIikNCiAgICAgICAgICAgICAgKSAlPiUNCiAgYWRkTGVnZW5kKHBhbCA9IHBhbCwgdmFsdWVzID0gfkFMQU5ELzIuNTllKzYsIHRpdGxlID0gIkFyZWEgKHNxLiBtaWxlcykiKSAlPiUNCiAgYWRkU2NhbGVCYXIocG9zaXRpb24gPSAiYm90dG9tcmlnaHQiKSAlPiUNCiAgYWRkRHJhd1Rvb2xiYXIoKQ0KYGBgDQoNCg0KDQoNCg==